home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Extensions / img / imgppmmodule.c < prev    next >
Text File  |  1995-12-21  |  14KB  |  576 lines

  1. /***********************************************************
  2. Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
  3. Amsterdam, The Netherlands.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Stichting Mathematisch
  12. Centrum or CWI not be used in advertising or publicity pertaining to
  13. distribution of the software without specific, written prior permission.
  14.  
  15. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16. THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  18. FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  21. OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  
  23. ******************************************************************/
  24.  
  25. #include "Python.h"
  26. #include "import.h"
  27. #include "ppm.h"
  28.  
  29. /* The image formats we support */
  30. static PyObject *format_rgb, *format_rgb_b2t, *format_choices;
  31. extern PyObject *getimgformat();    /* Get foirmat by name */
  32.  
  33. /*
  34. ** Since PBMPLUS error handling is abysmal (print message, exit),
  35. ** there is a modified version that has (slightly) better error
  36. ** handling. Contact jack@cwi.nl if you want it. Define PBMNEWERROR
  37. ** if you have the modified pbmplus.
  38. **
  39. ** If you don't have it the first pbm error will abort you python
  40. ** program.
  41. */
  42. #define PBMNEWERROR
  43.  
  44. #ifndef PBMNEWERROR
  45. #define PPM_END
  46. #define PPM_START if (0) {
  47. #define PPM_ENDSTART }
  48.  
  49. #else
  50.  
  51. #include <setjmp.h>
  52. jmp_buf ppmerrenv;
  53. char ppmerrstr[1000];
  54.  
  55. #define PPM_END pm_setmsghandler(0); pm_setexithandler(0);
  56. #define PPM_START if ( setjmp(ppmerrenv) != 0 ) { \
  57.         PyErr_SetString(errobject, ppmerrstr); \
  58.     *ppmerrstr = '\0'; \
  59.         PPM_END
  60. #define PPM_ENDSTART return 0; \
  61.     } \
  62.     pm_setmsghandler(my_pmerr); \
  63.     pm_setexithandler(my_pmexit);
  64.  
  65.  
  66. static void
  67. my_pmerr(str)
  68.     char *str;
  69. {
  70.     strncpy(ppmerrstr, str, 999);
  71. }
  72.  
  73. static void
  74. my_pmexit()
  75. {
  76.     longjmp(ppmerrenv, 1);
  77. }
  78.  
  79. #endif /* PBMNEWERROR */
  80.  
  81. /* Ppm objects */
  82.  
  83. typedef struct {
  84.     PyObject_HEAD
  85.     PyObject    *dict;        /* Attributes dictionary */
  86.     int    is_reader;    /* TRUE if this is a reader */
  87.     char    *filename;    /* filename of the image file */
  88.     FILE    *filep;
  89.     pixval    maxval;
  90.     int    format;
  91. } ppmobject;
  92.  
  93. static PyObject *errobject;
  94.  
  95. staticforward PyTypeObject Ppmtype;
  96.  
  97. #define is_ppmobject(v)        ((v)->ob_type == &Ppmtype)
  98.  
  99. static char doc_ppm[] = "This object reads/writes PPM files\n"
  100.     "The 'width', 'height' and 'format' attributes describe the picture\n"
  101.     "For writers, setting 'forceplain' creates an ASCII PPM file.";
  102.  
  103. /* Routine to easily obtain C data from the dict python data */
  104. int
  105. ppmselfattr(self, name, fmt, ptr, wanterr)
  106.     ppmobject *self;
  107.     char *name;
  108.     char *fmt;
  109.     void *ptr;
  110.     int wanterr;
  111. {
  112.     PyObject *obj;
  113.     char errbuf[100];
  114.  
  115.     obj = PyDict_GetItemString(self->dict, name);
  116.     if ( obj == NULL ) {
  117.     if ( wanterr ) {
  118.         sprintf(errbuf, "Required attribute '%s' not set", name);
  119.         PyErr_SetString(errobject, errbuf);
  120.         return 0;
  121.     } else {
  122.         PyErr_Clear();
  123.         return 0;
  124.     }
  125.     }
  126.     if ( !PyArg_Parse(obj, fmt, ptr) ) {
  127.     if ( !wanterr )
  128.         PyErr_Clear();
  129.     return 0;
  130.     }
  131.     return 1;
  132. }
  133.  
  134. /* Routine to easily insert integer into dictionary */
  135. ppmsetintattr(self, name, value)
  136.     ppmobject *self;
  137.     char *name;
  138.     int value;
  139. {
  140.     PyObject *obj;
  141.     int rv;
  142.  
  143.     obj = PyInt_FromLong(value);
  144.     rv = PyDict_SetItemString(self->dict, name, obj);
  145.     Py_DECREF(obj);
  146.     return rv;
  147. }
  148.  
  149. static ppmobject *
  150. newppmobject()
  151. {
  152.     ppmobject *xp;
  153.     xp = PyObject_NEW(ppmobject, &Ppmtype);
  154.     if (xp == NULL)
  155.         return NULL;
  156.     xp->dict = PyDict_New();
  157.     xp->filename = NULL;
  158.     xp->filep = NULL;
  159.     return xp;
  160. }
  161.  
  162. static int
  163. initppmreader(self, name)
  164.     ppmobject *self;
  165.     char *name;
  166. {
  167.     char *name_copy;
  168.     int cols, rows;
  169.     pixval old_pbmmaxval;
  170.  
  171.     if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
  172.     PyErr_NoMemory();
  173.     return 0;
  174.     }
  175.     strcpy(name_copy, name);
  176.     self->filename = name_copy;
  177.     self->is_reader = 1;
  178.  
  179.     if ((self->filep = fopen(self->filename, "rb")) == NULL ) {
  180.     PyErr_SetFromErrno(PyExc_IOError);
  181.     return 0;
  182.     }
  183.     PPM_START
  184.     fclose(self->filep);
  185.         self->filep = 0;
  186.     return 0;
  187.     PPM_ENDSTART
  188.     old_pbmmaxval = ppm_pbmmaxval;
  189.     ppm_pbmmaxval = 0xff;   /* XXXX Correct for rgb/rgb_b2t formats */
  190.     ppm_readppminit(self->filep, &cols, &rows, &self->maxval,
  191.             &self->format);
  192.     ppm_pbmmaxval = old_pbmmaxval;
  193.     PPM_END
  194.  
  195.     ppmsetintattr(self, "width", cols);
  196.     ppmsetintattr(self, "height", rows);
  197.     PyDict_SetItemString(self->dict, "format", format_rgb);
  198.     PyDict_SetItemString(self->dict, "format_choices", format_choices);
  199.     if ( PyErr_Occurred() )
  200.     return 0;
  201.     return 1;
  202. }
  203.  
  204. static int
  205. initppmwriter(self, name)
  206.     ppmobject *self;
  207.     char *name;
  208. {
  209.     char *name_copy;
  210.  
  211.     if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
  212.     PyErr_NoMemory();
  213.     return 0;
  214.     }
  215.     strcpy(name_copy, name);
  216.     self->filename = name_copy;
  217.     self->filep = NULL;
  218.     self->is_reader = 0;
  219.     PyDict_SetItemString(self->dict, "format", format_rgb);
  220.     PyDict_SetItemString(self->dict, "format_choices", format_choices);
  221.     if( PyErr_Occurred())
  222.     return 0;
  223.     return 1;
  224. }
  225.  
  226. /* Ppm methods */
  227.  
  228. static void
  229. ppm_dealloc(xp)
  230.     ppmobject *xp;
  231. {
  232.     Py_XDECREF(xp->dict);
  233.     if( xp->filename )
  234.         free(xp->filename);
  235.     if( xp->filep )
  236.         fclose(xp->filep);
  237.     PyMem_DEL(xp);
  238. }
  239.  
  240. static char doc_read[] = "Read the actual data, returns a string";
  241.  
  242. static PyObject *
  243. ppm_read(self, args)
  244.     ppmobject *self;
  245.     PyObject *args;
  246. {
  247.         int i, w, h, toptobottom, rowlen;
  248.     PyObject *rv;
  249.     long *datap;
  250.     pixel *pixelrow;
  251.     pixel ppmpixel;
  252.     long rgbpixel;
  253.     PyObject *fmt;
  254.     
  255.     if (!PyArg_ParseTuple(args,""))
  256.         return NULL;
  257.     if (!self->is_reader) {
  258.         PyErr_SetString(errobject, "Cannot read() from writer object");
  259.         return NULL;
  260.     }
  261.     /* XXXX Read data and return it */
  262.     /* XXXX Get args from self->dict and write the data */
  263.     if ( !ppmselfattr(self, "width", "i", &w, 1) ||
  264.          !ppmselfattr(self, "height", "i", &h, 1) ||
  265.          !ppmselfattr(self, "format", "O", &fmt, 1) )
  266.         return NULL;
  267.     if ( fmt == format_rgb )
  268.         toptobottom = 1;
  269.     else if ( fmt == format_rgb_b2t )
  270.         toptobottom = 0;
  271.     else {
  272.         PyErr_SetString(errobject, "Unsupported image format");
  273.         return NULL;
  274.     }
  275.     pixelrow = 0;
  276.     rv = 0;
  277.     PPM_START
  278.         if ( pixelrow )
  279.         pbm_freerow(pixelrow);
  280.         if ( rv )
  281.         Py_DECREF(rv);
  282.         return NULL;
  283.     PPM_ENDSTART
  284.  
  285.     pixelrow=ppm_allocrow(w);
  286.     if ( (rv=PyString_FromStringAndSize(0, w*h*4)) == NULL ) {
  287.         pbm_freerow(pixelrow);
  288.         return NULL;
  289.     }
  290.     datap = (long *)PyString_AsString(rv);
  291.  
  292.     if ( toptobottom ) {
  293.         rowlen = w;
  294.     } else {
  295.         rowlen = -w;
  296.         datap = datap + w*(h-1);
  297.     }
  298.  
  299.     while( h > 0 ) {
  300.         ppm_readppmrow(self->filep, pixelrow, w, self->maxval,
  301.                self->format);
  302.         for(i=0; i<w; i++) {
  303.         ppmpixel = pixelrow[i];
  304.         rgbpixel = PPM_GETR(ppmpixel);
  305.         rgbpixel |= (PPM_GETG(ppmpixel)) << 8;
  306.         rgbpixel |= (PPM_GETB(ppmpixel)) << 16;
  307.         datap[i] = rgbpixel;
  308.         }
  309.         datap += rowlen;
  310.         h -= 1;
  311.     }
  312.         PPM_END
  313.     pbm_freerow(pixelrow);
  314.     return rv;
  315. }
  316.  
  317. static char doc_write[] = "Write (string) data to the PPM file";
  318.  
  319. static PyObject *
  320. ppm_write(self, args)
  321.     ppmobject *self;
  322.     PyObject *args;
  323. {
  324.         long *data;
  325.     int datalen;
  326.     int i, w, h, rowlen;
  327.     PyObject *fmt;
  328.     int toptobottom;
  329.     pixel *pixelrow;
  330.     pixel ppmpixel;
  331.     long rgbpixel;
  332.     int forceplain;
  333.     FILE *filep;
  334.     
  335.     if (!PyArg_ParseTuple(args, "s#", &data, &datalen))
  336.         return NULL;
  337.     if (self->is_reader) {
  338.         PyErr_SetString(errobject, "Cannot write() to reader object");
  339.         return NULL;
  340.     }
  341.     /* XXXX Get args from self->dict and write the data */
  342.     if ( !ppmselfattr(self, "width", "i", &w, 1) ||
  343.          !ppmselfattr(self, "height", "i", &h, 1) ||
  344.          !ppmselfattr(self, "format", "O", &fmt, 1) )
  345.         return NULL;
  346.     if( w*h*4 != datalen ) {
  347.         PyErr_SetString(errobject, "Incorrect datasize");
  348.         return NULL;
  349.     }
  350.     forceplain = 0;
  351.     ppmselfattr(self, "forceplain", "i", &forceplain, 0);
  352.     
  353.     if ( fmt == format_rgb ) {
  354.         toptobottom = 1;
  355.         rowlen = w;
  356.     } else if ( fmt == format_rgb_b2t ) {
  357.         toptobottom = 0;
  358.         rowlen = -w;
  359.         data = data + w*(h-1);
  360.     } else {
  361.         PyErr_SetString(errobject, "Unsupported image format");
  362.         return NULL;
  363.     }
  364.     if ((filep = fopen(self->filename, forceplain?"w":"wb")) == NULL) {
  365.         PyErr_SetFromErrno(PyExc_IOError);
  366.         return 0;
  367.     }
  368. #ifdef macintosh
  369.     setfiletype(self->filename, '????', 'PPGM');
  370. #endif
  371.     pixelrow = 0;
  372.     PPM_START
  373.         if ( pixelrow )
  374.         pbm_freerow(pixelrow);
  375.         fclose(filep);
  376.         return NULL;
  377.     PPM_ENDSTART
  378.  
  379.     pixelrow=ppm_allocrow(w);
  380.  
  381.     ppm_writeppminit(filep, w, h, 0xff, forceplain);
  382.     while( h > 0 ) {
  383.         for(i=0; i<w; i++) {
  384.         rgbpixel = data[i];
  385.         PPM_ASSIGN(ppmpixel, rgbpixel&0xff, (rgbpixel>>8) & 0xff,
  386.                (rgbpixel>>16)&0xff);
  387.         pixelrow[i] = ppmpixel;
  388.         }
  389.         ppm_writeppmrow(filep, pixelrow, w, 0xff, forceplain);
  390.         data += rowlen;
  391.         h -= 1;
  392.     }
  393.     PPM_END
  394.     pbm_freerow(pixelrow);
  395.     if (fclose(filep) != 0) {
  396.         PyErr_SetFromErrno(PyExc_IOError);
  397.         return NULL;
  398.     }
  399.     Py_INCREF(Py_None);
  400.     return Py_None;
  401. }
  402.  
  403. static struct PyMethodDef ppm_methods[] = {
  404.     {"read",    (PyCFunction)ppm_read,    1,    doc_read},
  405.     {"write",    (PyCFunction)ppm_write,    1,    doc_write},
  406.     {NULL,        NULL}        /* sentinel */
  407. };
  408.  
  409. static PyObject *
  410. ppm_getattr(xp, name)
  411.     ppmobject *xp;
  412.     char *name;
  413. {
  414.         PyObject *v;
  415.     
  416.     if (xp->dict != NULL) {
  417.             if ( strcmp(name, "__dict__") == 0 ) {
  418.                 Py_INCREF(xp->dict);
  419.             return xp->dict;
  420.         }
  421.                if ( strcmp(name, "__doc__") == 0 ) {
  422.                 return PyString_FromString(doc_ppm);
  423.         }
  424.         v = PyDict_GetItemString(xp->dict, name);
  425.         if (v != NULL) {
  426.             Py_INCREF(v);
  427.             return v;
  428.         }
  429.     }
  430.     return Py_FindMethod(ppm_methods, (PyObject *)xp, name);
  431. }
  432.  
  433. static int
  434. ppm_setattr(xp, name, v)
  435.     ppmobject *xp;
  436.     char *name;
  437.     PyObject *v;
  438. {
  439.     if (xp->dict == NULL) {
  440.         xp->dict = PyDict_New();
  441.         if (xp->dict == NULL)
  442.             return -1;
  443.     }
  444.     if (v == NULL) {
  445.         int rv = PyDict_DelItemString(xp->dict, name);
  446.         if (rv < 0)
  447.             PyErr_SetString(PyExc_AttributeError,
  448.                     "delete non-existing imgppm attribute");
  449.         return rv;
  450.     }
  451.     else
  452.         return PyDict_SetItemString(xp->dict, name, v);
  453. }
  454.  
  455. static PyTypeObject Ppmtype = {
  456.     PyObject_HEAD_INIT(&PyType_Type)
  457.     0,            /*ob_size*/
  458.     "imgppm",        /*tp_name*/
  459.     sizeof(ppmobject),    /*tp_basicsize*/
  460.     0,            /*tp_itemsize*/
  461.     /* methods */
  462.     (destructor)ppm_dealloc, /*tp_dealloc*/
  463.     0,            /*tp_print*/
  464.     (getattrfunc)ppm_getattr, /*tp_getattr*/
  465.     (setattrfunc)ppm_setattr, /*tp_setattr*/
  466.     0,            /*tp_compare*/
  467.     0,            /*tp_repr*/
  468.     0,            /*tp_as_number*/
  469.     0,            /*tp_as_sequence*/
  470.     0,            /*tp_as_mapping*/
  471.     0,            /*tp_hash*/
  472. };
  473.  
  474. static char doc_newreader[] =
  475.     "Return an object that reads the PPM/PGM/PBM file passed as argument";
  476.  
  477. static PyObject *
  478. ppm_newreader(self, args)
  479.     PyObject *self;
  480.     PyObject *args;
  481. {
  482.         char *filename;
  483.     ppmobject *obj;
  484.     
  485.     if (!PyArg_ParseTuple(args, "s", &filename))
  486.         return NULL;
  487.     if ((obj = newppmobject()) == NULL)
  488.         return NULL;
  489.     if ( !initppmreader(obj, filename) ) {
  490.         ppm_dealloc(obj);
  491.         return NULL;
  492.     }
  493.     return (PyObject *)obj;
  494. }
  495.  
  496. static char doc_newwriter[] =
  497.     "Return an object that writes the PPM file passed as argument";
  498.  
  499. static PyObject *
  500. ppm_newwriter(self, args)
  501.     PyObject *self;
  502.     PyObject *args;
  503. {
  504.         char *filename;
  505.     ppmobject *obj;
  506.     
  507.     if (!PyArg_ParseTuple(args, "s", &filename))
  508.         return NULL;
  509.     if ((obj = newppmobject()) == NULL)
  510.         return NULL;
  511.     if ( !initppmwriter(obj, filename) ) {
  512.         ppm_dealloc(obj);
  513.         return NULL;
  514.     }
  515.     return (PyObject *)obj;
  516. }
  517.  
  518.  
  519. /* List of functions defined in the module */
  520.  
  521. static struct PyMethodDef ppm_module_methods[] = {
  522.     {"reader",    ppm_newreader,    1,    doc_newreader},
  523.     {"writer",    ppm_newwriter,    1,    doc_newwriter},
  524.     {NULL,        NULL}        /* sentinel */
  525. };
  526.  
  527.  
  528. /* Initialization function for the module (*must* be called initimgppm) */
  529. static char doc_imgppm[] =
  530.   "Module that reads images from PPM/PGM/PBM files and writes to PPM files.";
  531.  
  532. void
  533. initimgppm()
  534. {
  535.     PyObject *m, *d, *x, *formatmodule, *formatdict;
  536.  
  537.     /* Create the module and add the functions */
  538.     m = Py_InitModule("imgppm", ppm_module_methods);
  539.  
  540.     /* Add some symbolic constants to the module */
  541.     d = PyModule_GetDict(m);
  542.     errobject = PyString_FromString("imgppm.error");
  543.     PyDict_SetItemString(d, "error", errobject);
  544.     x = PyString_FromString(doc_imgppm);
  545.     PyDict_SetItemString(d, "__doc__", x);
  546.  
  547.     /* Get supported formats */
  548.     if ((formatmodule = PyImport_ImportModule("imgformat")) == NULL)
  549.         Py_FatalError("imgppm depends on imgformat");
  550.     if ((formatdict = PyModule_GetDict(formatmodule)) == NULL)
  551.         Py_FatalError("imgformat has no dict");
  552.  
  553.     format_rgb = PyDict_GetItemString(formatdict,"rgb");
  554.     format_rgb_b2t = PyDict_GetItemString(formatdict,"rgb_b2t");
  555.     format_choices = Py_BuildValue("(OO)", format_rgb, format_rgb_b2t);
  556.  
  557.     /* Initialize pbmplus */
  558.         {
  559.         int ppm_argc;
  560.         static char *ppm_arglist[] = { "pbmplus", 0};
  561.         char **ppm_argv;
  562.  
  563.         ppm_argc = 1;
  564.         ppm_argv = ppm_arglist;
  565.         PPM_START /* { */
  566.         Py_FatalError("pbmplus initialization error");
  567.         } /* PPM_ENDSTART won't work here, it has return NULL */
  568.         ppm_init(&ppm_argc, ppm_argv);
  569.         PPM_END
  570.     }
  571.  
  572.     /* Check for errors */
  573.     if (PyErr_Occurred())
  574.         Py_FatalError("can't initialize module imgppm");
  575. }
  576.